<?php
/**
 * Nordic Repository
 * 
 * LICENSE
 * 
 * The new BSD license is applied on this source-file. For further
 * information please visit http://license.nordic-dev.de/newbsd.txt
 * or send an email to andre.moelle@gmail.com.
 */

/**
 * Necessary includes.
 */
Zend_Loader::loadClass('Zend_Controller_Plugin_Abstract');
Zend_Loader::loadClass('Nordic_Security_Protectable');

/**
 * This plugin is the most important for the protection, because
 * it handles and adds other protectors.
 * 
 * @category   Nordic
 * @package    Nordic_Security
 * @copyright  2007 Nordic Development
 * @license    http://license.nordic-dev.de/newbsd.txt (New-BSD license)
 * @author     Andre Moelle <andre.moelle@gmail.com>
 * @version    $Id: Protector.php 3 2007-07-08 09:21:42Z andre.moelle $
 */
class Nordic_Security_Protector extends Zend_Controller_Plugin_Abstract
{
	/**
	 * Default dispatcher.
	 * 
	 * @var Zend_Controller_Dispatcher_Interface
	 */
	private $_dispatcher;
	
	/**
	 * Installed protectors.
	 * 
	 * <code>
	 * $_protectors = array(
	 * 	'foo' => instance of a Nordic_Security_Protector_Abstract,
	 * 	'bar' => instance of a Nordic_Security_Protector_Abstract
	 * );
	 * </code>
	 * 
	 * @var array
	 */
	private $_protectors = array();
	
	/**
	 * Constructor sets the dispatcher.
	 * 
	 * @param Zend_Controller_Dispatcher_Interface $dispatcher dispatcher
	 * @return void
	 */
	public function __construct (Zend_Controller_Dispatcher_Interface $dispatcher)
	{
		$this->_dispatcher = $dispatcher;
	}
	
	/**
	 * Appends the controller to the internal list.
	 * 
	 * @param string $name name of the controller
	 * @param Nordic_Security_Protector_Abstract $protector new protector
	 * @return void
	 */
	public function appendProtector ($name, Nordic_Security_Protector_Abstract $protector)
	{
		$this->_protectors[$name] = $protector;
	}
	
	/**
	 * The active accessed controller should be protected.
	 * 
	 * @see Nordic_Security_Protector::protect()
	 */
    public function dispatchLoopStartup (Zend_Controller_Request_Abstract $request)
    {
		$this->protect($request->getControllerName());
    }
    
    /**
     * Returns the name of the controller.
     * 
     * @param string $name name of the controller
     * @return string
     */
    public function getController ($name)
    {
    	$dispatcher = $this->_dispatcher;
    	
    	$class = $dispatcher->formatControllerName($name);
    	
    	Zend_Loader::loadFile(
    		$class . '.php',
    		$dispatcher->getControllerDirectory(),
    		true
    	);
	
    	return $class;
    }
	
	/**
	 * Returns one protector.
	 * 
	 * @param string $name name of the controller
	 * @return Nordic_Security_Protector_Abstract
	 */
	public function getProtector ($name)
	{
		if(!$this->isProtected($name))
		{
			return null;
		}
		
		$arr = $this->getProtectors();
		
		return $arr[$name];
	}
	
	/**
	 * Returns each protector.
	 * 
	 * @param void
	 * @return array
	 */
	public function getProtectors ()
	{
		return $this->_protectors;
	}
	
	/**
	 * Installs a new protector.
	 * 
	 * This method adds the protector to the plugins, appends it to
	 * the internal protector-list and finally returns the controller.
	 * 
	 * @param string $name name of the controller
	 * @return Zend_Controller_Action
	 */
	public function installProtector ($name)
	{
		$class = $this->getController($name);
		$obj = new $class($this->getRequest(), $this->getResponse());
		
		$protector = $obj->getProtector();
		$this->appendProtector($name, $protector);
		$protector->setRequest($this->getRequest());
		$protector->setResponse($this->getResponse());
		
		
		try
		{
			$obj->getFrontController()->registerPlugin($this->getProtector($name));
		}
		catch (Zend_Controller_Exception $e)
		{
			;
		}
		
		return $obj;
	}
	
	/**
	 * Returns true if the class implements Nordic_Security_Protectable.
	 * 
	 * @param string $name name of the controller
	 * @return boolean
	 */
	public function isProtectable ($name)
	{
		try
		{
			$class = $this->getController($name);
			$refl = new ReflectionClass($class);
			
			return $refl->implementsInterface('Nordic_Security_Protectable');
		}
		catch (Zend_Exception $e)
		{
			return false;
		}
	}
	
	/**
	 * Returns true if the controller is already protected.
	 * 
	 * @param string $name name of the controller
	 * @return boolean
	 */
	public function isProtected ($name)
	{
		 return in_array($name, array_keys($this->getProtectors()));
	}
	
	/**
	 * If the controller has changed, it tries to protect the new controller.
	 * 
	 * @see Nordic_Security_Protector::protect()
	 */
    public function postDispatch (Zend_Controller_Request_Abstract $request)
	{
		$this->protect($request->getControllerName());
	}
	
	/**
	 * Protects a controller if he is not already protected or no protectable.
	 * 
	 * @param void
	 * @return void
	 */
	public function protect ($name)
	{
		if(!$this->isProtected($name) && $this->isProtectable($name))
		{
			$this->installProtector($name);
		}
	}
}
?>